package cn.demoncat.util.redis.util;

import cn.demoncat.util.redis.config.RedisIsolator;
import cn.demoncat.util.redis.entity.RedisKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.function.Supplier;

/**
 * Redis Set处理工具
 *
 * @author 延晓磊
 * @since 2021年02月13日
 */
@Component
public class RedisSetUtil {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private RedisExecuteUtil redisExecuteUtil;
    @Resource
    private RedisIsolator redisIsolator;

    /**
     * 获取Redis Set
     *
     * 1、如果set有元素，exists 为true，否则为false
     *
     * 添加元素		add(e)		Set不存在时创建
     * 获取集合		members()	Set不存在时返回[]
     * 集合长度		size()
     * 删除元素		remove(e)
     * 随机获取元素	randomMember()
     * 随机移除元素	pop()
     * 是否包含元素	isMember(e)	Set不存在返回false
     *
     * @param key
     * @return
     *
     * @author 延晓磊
     * @since 2021年02月10日
     */
    public BoundSetOperations<String, String> set(String key){
        return stringRedisTemplate.boundSetOps(redisIsolator.getKey(key));
    }

    /**
     * 判断SET是否包含元素
     *
     * SISMEMBER key val
     *
     * @param key	Set。key
     * @param val	Set.member
     *
     * @return
     */
    public Boolean isMember(String key, String val){
        return set(key).isMember(val);
    }

    /**
     * 判断SET是否包含元素
     *
     * SISMEMBER key val || EXISTS key
     *
     * @param key	Set。key
     * @param val	Set.member
     * @param fn	缓存不存在时调用（查询数据，重置SET，返回结果）
     *
     * @return
     */
    public Boolean isMember(String key, String val, Supplier<Boolean> fn){
        // 2 值存在，1 值不存在，0 SET不存在
        long r = redisExecuteUtil.execute(Long.class,"if (redis.call('SISMEMBER',KEYS[1],ARGV[1]) == 1) then return 2 else return redis.call('EXISTS',KEYS[1]) end", key, val);
        if (r == 2) {
            return true;
        }
        if (r == 1) {
            return false;
        }
        return fn.get();
    }

    /**
     * 重置SET的元素
     *
     * del key && sadd key val
     *
     * @param key	Set。key
     * @param val	Set.member，非空
     *
     * @return
     */
    public void resetMember(String key, String ... val){
        resetMember(key, null, val);
    }

    /**
     * 重置SET的元素
     *
     * del key && sadd key val && expire key
     *
     * @param key	Set。key
     * @param exp	expire
     * @param val	Set.member，非空
     *
     * @return
     */
    public void resetMember(String key, Integer exp, String ... val){
        // 批量执行
        final String realKey = redisIsolator.getKey(key);
        stringRedisTemplate.executePipelined((RedisCallback<Object>) redisConnection -> {
            StringRedisConnection connection = (StringRedisConnection)redisConnection;
            // 删除
            connection.del(realKey);
            // 重建
            connection.sAdd(realKey, val);
            // 过期时间
            if (exp != null && exp > 0) {
                connection.expire(realKey, exp);
            }
            return null;
        });
    }

    /**
     * 重置SET的元素
     *
     * del key && sadd key val && expire key
     *
     * @param key	Set。key
     * @param val	Set.member，非空
     *
     * @return
     */
    public void resetMember(RedisKey key, String ... val){
        resetMember(key.getKey(), key.getExp(), val);
    }
}
